import { defineStore } from 'pinia';
import { api, IResponse } from 'src/boot/axios';
import { plainToInstance } from 'class-transformer';
import Video from 'src/models/Video';
import Audio from 'src/models/Audio';
// import { Project } from 'src/pages/studio/StudioProject';
import { VideoJsPlayer } from 'video.js';
import { IPage } from 'boot/axios';
import Playlist from 'src/models/Playlist';
import { fancyTimeFormat } from 'src/utils/common';
export interface VideoStateInterface {
  indexVideos: Video[];
  featuredVideos: Video[];
  featuredVideosPage?: IPage;
  followedVideos: Video[];
  followedVideosPage?: IPage;
  videosByLanguages: Video[];
  videosByLanguagesPage?: IPage;
  discoverVideos: Video[];
  discoverVideosPage?: IPage;
  currentVideo: Video | null;
  currentReltedVideos?: Video[];
  originalAudio: Audio | null;
  currentAudio: Audio | null;
  currentTime: number;
  currentPlaylist?: Playlist[];
  duration: number;
  isPlaying: boolean;
  isRecording: boolean;
  videoVolume: number;
  recordVolume: number;
  originalVolume: number;
  zoom: number;
  videoInstance: VideoJsPlayer | null;
  videoElement: HTMLVideoElement | null;
  currentProject: any | null;
  projectName: string;
  videoPageMiniMode: boolean;
}
function datas2Model<T>(data: T[], model: any) {
  return data.map((item) => {
    return plainToInstance<T, any>(model, item);
  });
}
export const useVideoStore = defineStore('video', {
  state: (): VideoStateInterface => ({
    currentVideo: null,
    indexVideos: [],
    featuredVideos: [],
    followedVideos: [],
    videosByLanguages: [],
    discoverVideos: [],
    currentTime: 0,
    duration: 1,
    isPlaying: false,
    isRecording: false,
    zoom: 1,
    originalVolume: 1,
    videoVolume: 1,
    recordVolume: 1,
    videoInstance: null,
    videoElement: null,
    currentProject: null,
    projectName: 'untitled',
    videoPageMiniMode: false,
    currentAudio: null,
    originalAudio: null,
  }),
  getters: {
    currentTimeStr({ currentTime }) {
      return fancyTimeFormat(currentTime);
    },
    durationStr({ duration }) {
      return fancyTimeFormat(duration);
    },
  },
  actions: {
    setFeaturedVideos(videos: Video[]) {
      if (videos.length > 0) {
        this.featuredVideos = videos.map((video) => {
          return plainToInstance(Video, video);
        });
      }
    },
    setFeaturedVideosPage(page: IPage) {
      this.featuredVideosPage = page;
    },
    setVideoByFollowed(videos: Video[]) {
      if (videos.length > 0) {
        this.followedVideos = videos.map((video) => {
          return plainToInstance(Video, video);
        });
      }
    },
    setVideoByFollowedPage(page: IPage) {
      this.followedVideosPage = page;
    },
    setVideoByLanguages(videos: Video[]) {
      if (videos.length > 0) {
        this.videosByLanguages = videos.map((video) => {
          return plainToInstance(Video, video);
        });
      }
    },
    setVideoByLanguagesPage(page: IPage) {
      this.videosByLanguagesPage = page;
    },
    setDiscoverVideos(videos: Video[]) {
      if (videos.length > 0) {
        this.discoverVideos = videos.map((video) => {
          return plainToInstance(Video, video);
        });
      }
    },
    setDiscoverVideosPage(page: IPage) {
      this.discoverVideosPage = page;
    },
    setCurrentVideo(v: Video) {
      const video = plainToInstance(Video, v);
      this.originalAudio = video.audios.filter((a) => a.isOriginal)[0];
      this.currentAudio = video.audios[0];
      this.currentVideo = video;
    },
    setOriginalAudio(audio: Audio) {
      this.originalAudio = plainToInstance(Audio, audio);
    },
    updateOriginalAudioVolume(volume: number) {
      this.originalVolume = volume;
    },
    setCurrentAudio(audio: Audio) {
      this.currentAudio = plainToInstance(Audio, audio);
    },
    setCurrentPlaylist(playlist: Playlist[]) {
      this.currentPlaylist = plainToInstance(Playlist, playlist);
    },
    setCurrentAudioById(id: string) {
      if (
        this.currentVideo &&
        this.currentVideo.audios &&
        this.currentVideo.audios.length > 0
      ) {
        const audio = this.currentVideo.audios.find((audio) => audio.id === id);
        if (audio) {
          this.currentAudio = audio;
        }
      }
    },
    setCurrentAudioByLang(lang: string) {
      if (
        this.currentVideo &&
        this.currentVideo.audios &&
        this.currentVideo.audios.length > 0
      ) {
        const audio = this.currentVideo.audios.find(
          (audio) => audio.langCode === lang
        );
        if (audio) {
          this.currentAudio = audio;
        }
      }
    },
    setVideoLikeOrDislike({
      likeCount,
      dislikeCount,
      isLiked,
      isDisliked,
    }: any) {
      // should get only like or dislike info
      if (this.currentVideo) {
        this.currentVideo.isLiked = isLiked;
        this.currentVideo.likeCount = likeCount;
        this.currentVideo.isDisliked = isDisliked;
        this.currentVideo.dislikeCount = dislikeCount;
      }
    },
    setCurrnetTime(value: number) {
      this.currentTime = value;
    },
    setDuration(value: number) {
      this.duration = value;
    },
    setZoom(value: number) {
      this.zoom = value;
    },
    updateVideoState(value: boolean) {
      this.isPlaying = value;
    },
    updateVideoVolume(value: number) {
      this.videoVolume = value;
    },
    updateRecordVolume(value: number) {
      this.recordVolume = value;
    },
    updateRecordState(value: boolean) {
      this.isRecording = value;
    },
    updateVideoInstance(instance: VideoJsPlayer | null) {
      this.videoInstance = instance;
    },
    updateVideoElement(videoEl: HTMLVideoElement | null) {
      this.videoElement = videoEl;
    },
    destoryVideoInstance() {
      if (this.videoInstance) {
        this.videoInstance.dispose();
        this.videoInstance = null;
      }
    },
    togglePlay() {
      if (this.videoInstance) {
        if (this.isPlaying) {
          this.videoInstance.pause();
          this.isPlaying = false;
        } else {
          this.videoInstance.play();
          this.isPlaying = true;
        }
      }
    },
    playCurrentVideo() {
      if (this.videoInstance) {
        if (!this.isPlaying) {
          this.videoInstance.play();
          this.isPlaying = true;
        }
      }
    },
    pauseCurrentVideo() {
      if (this.videoInstance) {
        if (this.isPlaying) {
          this.videoInstance.pause();
          this.isPlaying = false;
        }
      }
    },
    forwards(seconds = 10) {
      if (this.videoInstance) {
        this.videoInstance.currentTime(
          this.videoInstance.currentTime() + seconds
        );
      }
    },
    backwards(seconds = 10) {
      if (this.videoInstance) {
        this.videoInstance.currentTime(
          this.videoInstance.currentTime() - seconds
        );
      }
    },
    seekTo(seconds = 0) {
      if (this.videoInstance) {
        this.videoInstance.currentTime(seconds);
      }
    },
    setProjectName(name: string) {
      this.projectName = name;
    },
    setCurrentReltedVideos(videos: Video[]) {
      this.currentReltedVideos = plainToInstance(Video, videos);
    },
    setVideoPageMiniMode(value: boolean) {
      this.videoPageMiniMode = value;
    },
    async getFeaturedVideos(params?: { page: number; size: number }) {
      const { code, data, msg, page } = await api.post<any, IResponse<Video[]>>(
        '/videos',
        params
      );
      if (code === 200) {
        if (data.length > 0) {
          this.featuredVideos = data.map((video) => {
            return plainToInstance(Video, video);
          });
          this.featuredVideos = datas2Model<Video>(data, Video);
        }
        this.featuredVideosPage = page;
      } else {
        throw new Error(msg);
      }
    },
    async getDiscoverVideos(params: { page: number; size: number }) {
      const { code, data, msg, page } = await api.post<any, IResponse<Video[]>>(
        '/videos/discover',
        params
      );
      if (code === 200) {
        if (data.length > 0) {
          this.discoverVideos = datas2Model<Video>(data, Video);
        }
        this.discoverVideosPage = page;
      } else {
        throw new Error(msg);
      }
    },
    async getVideosByLanguage(params: {
      page: number;
      size: number;
      languages: string[];
    }) {
      const { code, data, msg, page } = await api.post<any, IResponse<Video[]>>(
        '/videos',
        params
      );
      if (code === 200) {
        if (data.length > 0) {
          this.videosByLanguages = datas2Model<Video>(data, Video);
        }
        this.videosByLanguagesPage = page;
      } else {
        throw new Error(msg);
      }
    },
    async getVideoByFollowed(params?: { page: number; size: number }) {
      const { code, data, msg, page } = await api.post<any, IResponse<Video[]>>(
        '/videos',
        params
      );
      if (code === 200) {
        if (data.length > 0) {
          this.followedVideos = datas2Model<Video>(data, Video);
        }
        this.followedVideosPage = page;
      } else {
        throw new Error(msg);
      }
    },
    changeVideoPlayState(value: boolean) {
      if (value) {
        this.videoInstance?.play();
      } else {
        this.videoInstance?.pause();
      }
    },
    setCurrentVideoLikeInfo(info: any) {
      // should get only like or dislike info
      if (this.currentVideo) {
        this.currentVideo.isLiked = info.isLiked;
        this.currentVideo.likeCount = info.likeCount;
        this.currentVideo.isDisliked = info.isDisliked;
        this.currentVideo.dislikeCount = info.dislikeCount;
      }
    },
    async toggleLikeVideo(videoId: string) {
      const { code, data, msg } = await api.post<any, IResponse<any>>(
        `/video/like/${videoId}`,
        {
          id: videoId,
        }
      );
      if (code === 200) {
        this.setCurrentVideoLikeInfo(data);
      } else {
        return new Error(msg);
      }
    },
    async toggleDislikeVideo(videoId: string) {
      const { code, data, msg } = await api.post<any, IResponse<any>>(
        `/video/dislike/${videoId}`,
        {
          id: videoId,
        }
      );
      if (code === 200) {
        this.setCurrentVideoLikeInfo(data);
      } else {
        return new Error(msg);
      }
    },
    async getVideoAndPlay(videoId: string) {
      const data = await api.get<any, IResponse<Video>>(`/video/${videoId}`);
      if (data.code === 200) {
        this.setCurrentVideo(data.data);
      } else {
        throw new Error(data.msg);
      }
    },
    async getAudioAndPlay(audioId: string) {
      const { code, data, msg } = await api.get<any, IResponse<Audio>>(
        `/audio/${audioId}`
      );
      if (code === 200) {
        const audio = plainToInstance(Audio, data);
        const videoResponse = await api.get<any, IResponse<Video>>(
          `/audio/${audio.videoId}`
        );
        if (videoResponse.code === 200) {
          this.setCurrentVideo(videoResponse.data);
        } else {
          throw new Error(videoResponse.msg);
        }
      } else {
        throw new Error(msg);
      }
    },
    async getPlaylistAndPlay(playlistId: string) {
      const { code, data, msg } = await api.get<any, IResponse<Playlist[]>>(
        `/playlist/${playlistId}`
      );
      if (code === 200) {
        this.currentPlaylist = plainToInstance(Playlist, data);
        const playlist = this.currentPlaylist[0]; // TODO maybe this playlist did't at first place
        if (playlist && playlist.contents.length > 0) {
          this.setCurrentVideo(playlist.contents[0]);
        }
      } else {
        throw new Error(msg);
      }
    },
    async getAudio(audioId: string): Promise<Audio> {
      const { code, data, msg } = await api.get<any, IResponse<Audio>>(
        `/audio/${audioId}`
      );
      if (code === 200) {
        return plainToInstance(Audio, data);
      } else {
        throw new Error(msg);
      }
    },
    async getVideo(params: {
      videoId: string;
      audioId?: string;
      langCode?: string;
    }): Promise<Video> {
      const { code, data, msg } = await api.get<any, IResponse<Video>>(
        `/video/${params.videoId}`,
        {
          params: {
            audioId: params.audioId,
            langCode: params.langCode,
          },
        }
      );
      if (code === 200) {
        return plainToInstance(Video, data);
      } else {
        throw new Error(msg);
      }
    },
    async getPlaylist(playlistId: string) {
      const { code, data, msg } = await api.get<any, IResponse<Playlist>>(
        `/playlist/${playlistId}`
      );
      if (code === 200) {
        return plainToInstance(Playlist, data);
      } else {
        throw new Error(msg);
      }
    },
    async getCurrentReltedVideos(id: string) {
      const { code, data, msg } = await api.get<any, IResponse<Video[]>>(
        `/videos/related/${id}`
      );
      if (code === 200) {
        this.currentReltedVideos = plainToInstance(Video, data);
      } else {
        throw new Error(msg);
      }
    },
  },
});
